home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Auge 4000 / Auge 4000 #51 (1990-12-01)(Amiga User Gruppe Einzugsgebiet 4000).zip / Auge 4000 #51 (1990-12-01)(Amiga User Gruppe Einzugsgebiet 4000).adf / Msh / src / device.c < prev    next >
C/C++ Source or Header  |  1990-12-01  |  19KB  |  809 lines

  1. /*-
  2.  * $Id: device.c,v 1.5 90/01/27 20:34:43 Rhialto Exp $
  3.  * $Log:    device.c,v $
  4.  * Revision 1.5  90/01/27  20:34:43  Rhialto
  5.  * Commented out #undef DEBUG
  6.  * 
  7.  * Revision 1.4  90/01/23  00:24:50  Rhialto
  8.  * io_Error=0 for immediate commands
  9.  *
  10.  * Revision 1.3  89/12/17  21:29:37  Rhialto
  11.  * Revision 1.1  89/12/17  20:03:55  Rhialto
  12.  *
  13.  * DEVICE.C
  14.  *
  15.  * The messydisk.device code that makes it a real Exec .device.
  16.  * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  17.  *
  18.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  19.  * not be used or copied without a licence.
  20. -*/
  21.  
  22. #include "dev.h"
  23. #include "device.h"
  24.  
  25. /*#undef DEBUG            /**/
  26. #ifdef DEBUG
  27. #   define    debug(x)  dbprintf x
  28. #else
  29. #   define    debug(x)
  30. #endif
  31.  
  32. /*
  33.  * The first executable location. This should return an error in case
  34.  * someone tried to run you as a program (instead of loading you as a
  35.  * device)
  36.  */
  37. /* INDENT OFF */
  38. #asm
  39.     moveq.l #20,d0
  40.     rts
  41. #endasm
  42. /* INDENT ON */
  43.  
  44. /*
  45.  * A romtag structure. Both "exec" and "ramlib" look for this structure to
  46.  * discover magic constants about you (such as where to start running you
  47.  * from...).
  48.  */
  49. /* INDENT OFF */
  50. #asm
  51.     public    __H0_end
  52. _EndCode equ    __H0_end
  53.     public    _RomTag
  54. _RomTag:
  55.     dc.w    $4AFC        ; RTC_MATCHWORD
  56.     dc.l    _RomTag     ; rt_MatchTag
  57.     dc.l    __H0_end    ; rt_EndSkip
  58.     dc.b    0        ; rt_Flags (no RTF_AUTOINIT)
  59.     dc.b    VERSION     ; rt_Version
  60.     dc.b    3        ; rt_Type  NT_DEVICE
  61.     dc.b    RTPRI        ; rt_Pri
  62.     dc.l    _DevName    ; rt_Name
  63.     dc.l    _idString    ; rt_IdString
  64.     dc.l    _Init        ; rt_Init
  65. #endasm
  66. /* INDENT ON */
  67.  
  68. char        DevName[] = "messydisk.device";
  69. char        idString[] = "messydisk.device $Revision: 1.5 $ $Date: 90/01/27 20:34:43 $\r\n";
  70.  
  71. /*
  72.  * -30-6*X  Library vectors:
  73.  */
  74.  
  75. void        (*LibVectors[]) () =
  76. {
  77.     _DevOpen, _DevClose, _DevExpunge, _LibNull,
  78.  
  79.     _DevBeginIO,
  80.     _DevAbortIO,
  81.     (void (*) ()) -1
  82. };
  83.  
  84. /*
  85.  * Device commands:
  86.  */
  87.  
  88. void        (*funcTable[]) () = {
  89.     CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  90.     CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  91.     TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  92.     TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  93.     TD_Remchangeint,
  94. };
  95.  
  96. /*
  97.  * Here begin the system interface commands. When the user calls
  98.  * OpenDevice/CloseDevice/RemDevice, this eventually gets trahslated into
  99.  * a call to the following routines (Open/Close/Expunge).  Exec has
  100.  * already put our device pointer in A6 for us.  Exec has turned off task
  101.  * switching while in these routines (via Forbid/Permit), so we should not
  102.  * take too long in them.
  103.  */
  104. /* INDENT OFF */
  105. #asm
  106.     public    _Init
  107. _Init:                ;a0=segment list
  108.     movem.l D2-D3/A0/A6,-(sp)
  109.     jsr    _CInit
  110.     movem.l (sp)+,D2-D3/A0/A6
  111.     rts
  112.  
  113.     public    __DevOpen
  114. __DevOpen:            ;d0=unitnum,d1=flags,a1=ioreq,a6=device
  115.     movem.l D0-D3/A1/A6,-(sp)
  116.     jsr    _DevOpen
  117.     movem.l (sp)+,D0-D3/A1/A6
  118.     rts
  119.  
  120.     public    __DevClose
  121. __DevClose:            ;a1=ioreq,a6=device
  122.     movem.l D2-D3/A1/A6,-(sp)
  123.     jsr    _DevClose
  124.     movem.l (sp)+,D2-D3/A1/A6
  125.     rts
  126.  
  127.     public    __DevExpunge
  128. __DevExpunge:            ;a6=device
  129.     movem.l D2-D3/A6,-(sp)
  130.     jsr    _DevExpunge
  131.     movem.l (sp)+,D2-D3/A6
  132.     rts
  133.  
  134.     public    __LibNull
  135. __LibNull:
  136.     clr.l    d0
  137.     rts
  138.  
  139.     public    __DevBeginIO
  140. __DevBeginIO:            ;a1=ioreq,a6=device
  141.     movem.l D2-D3/A1/A6,-(sp)
  142.     jsr    _DevBeginIO
  143.     movem.l (sp)+,D2-D3/A1/A6
  144.     rts
  145.  
  146.     public    __DevAbortIO
  147. __DevAbortIO:            ;a1=ioreq,a6=device
  148.     movem.l D2-D3/A1/A6,-(sp)
  149.     jsr    _DevAbortIO
  150.     movem.l (sp)+,D2-D3/A1/A6
  151.     rts
  152. #endasm
  153.  
  154. #ifdef HANDLE_IO_QUICK
  155. #asm
  156. ;;;;
  157. ;
  158. ;   C interface to the atomic set bit and test old value instruction.
  159. ;
  160. ;   Called as    BSET_ACTIVE(byte *address).
  161. ;
  162. ;   Old value of the bit returned all over d0.w
  163.  
  164. _BSET_ACTIVE:
  165.     move.l    4(sp),a0
  166.     bset    #0,(a0)         ; UNITB_ACTIVE
  167.     sne    d0
  168.     rts
  169.  
  170. #endasm
  171. #endif
  172. /* INDENT ON */
  173.  
  174. long        SysBase;    /* Argh! A global variable! */
  175.  
  176. /*
  177.  * The Initialization routine is given only a seglist pointer.    Since we
  178.  * are NOT AUTOINIT we must construct and add the device ourselves and
  179.  * return either NULL or the device pointer.  Exec has Forbid() for us
  180.  * during the call.
  181.  *
  182.  * If you have an extended device structure you must specify the size of the
  183.  * extended structure in MakeLibrary().
  184.  */
  185.  
  186. DEV           *
  187. CInit(D2, D3, segment)
  188. ulong        D2,
  189.         D3;
  190. long        segment;
  191. {
  192.     DEV        *dev;
  193.  
  194.     SysBase = *(long *) 4;
  195. #ifdef DEBUG
  196.     dbinit();
  197. #endif
  198.     dev = MakeLibrary(LibVectors, NULL, NULL, (long) sizeof (DEV), NULL);
  199.     if (DevInit(dev)) {
  200.     dev->dev_Node.ln_Type = NT_DEVICE;
  201.     dev->dev_Node.ln_Name = DevName;
  202.     dev->dev_Flags = LIBF_CHANGED | LIBF_SUMUSED;
  203.     dev->dev_Version = VERSION;
  204.     dev->dev_Revision = REVISION;
  205.     dev->dev_IdString = (APTR) idString;
  206.     dev->md_Seglist = segment;
  207.     AddDevice(dev);
  208.     return (dev);
  209.     }
  210.     FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  211.     return NULL;
  212. }
  213.  
  214. /*
  215.  * Open is given the device pointer, unitno and flags.    Either return the
  216.  * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  217.  * Forbid() for us during the call.
  218.  */
  219.  
  220. void
  221. DevOpen(unitno, flags, D2, D3, ioreq, dev)
  222. ulong        unitno;
  223. ulong        flags;
  224. ulong        D2,
  225.         D3;
  226. struct IOStdReq *ioreq;
  227. DEV           *dev;
  228. {
  229.     UNIT       *unit;
  230.  
  231.     debug(("OpenDevice unit %ld, flags %lx\n", unitno, flags));
  232.     if (unitno >= MD_NUMUNITS)
  233.     goto error;
  234.  
  235.     if ((unit = dev->md_Unit[unitno]) == NULL) {
  236.     if ((unit = UnitInit(dev, unitno)) == NULL)
  237.         goto error;
  238.     dev->md_Unit[unitno] = unit;
  239.     }
  240.     ioreq->io_Unit = (struct Unit *) unit;
  241.  
  242.     ++unit->mu_OpenCnt;
  243.     ++dev->dev_OpenCnt;
  244.     dev->dev_Flags &= ~LIBF_DELEXP;
  245.  
  246.     return;
  247.  
  248. error:
  249.     ioreq->io_Error = IOERR_OPENFAIL;
  250. }
  251.  
  252. /*
  253.  * Close is given the device pointer and the io request.  Be sure not to
  254.  * decrement the open count if already zero.    If the open count is or
  255.  * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  256.  * return the seglist.    Otherwise we return NULL.
  257.  *
  258.  * Note that this routine never sets LIBF_DELEXP on its own.
  259.  *
  260.  * Exec has Forbid() for us during the call.
  261.  */
  262.  
  263. long
  264. DevClose(D2, D3, ioreq, dev)
  265. ulong        D2,
  266.         D3;
  267. struct IOStdReq *ioreq;
  268. DEV           *dev;
  269. {
  270.     UNIT       *unit;
  271.  
  272.     unit = (UNIT *) ioreq->io_Unit;
  273.     debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  274.  
  275.     /*
  276.      * See if the unit is still in use. If not, close it down. This may
  277.      * need to do an update, which requires the ioreq.
  278.      */
  279.  
  280.     if (unit->mu_OpenCnt && --unit->mu_OpenCnt == 0) {
  281.     dev->md_Unit[unit->mu_UnitNr] = NULL;
  282.     UnitCloseDown(ioreq, dev, unit);
  283.     }
  284.     /*
  285.      * Make sure the ioreq is not used again.
  286.      */
  287.     ioreq->io_Unit = (void *) -1;
  288.     ioreq->io_Device = (void *) -1;
  289.  
  290.     if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  291.     return (NULL);
  292.     if (dev->dev_Flags & LIBF_DELEXP)
  293.     return (DevExpunge(D2, D3, dev));
  294.     return (NULL);
  295. }
  296.  
  297. /*
  298.  * We expunge the device and return the Seglist ONLY if the open count is
  299.  * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  300.  * flag and return NULL.
  301.  *
  302.  * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  303.  * called from the memory allocator and thus we CANNOT DO A Wait() or
  304.  * otherwise take a long time to complete (straight from RKM).
  305.  *
  306.  * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  307.  * freeze if we called it ourselves.  As far as I can tell from RKM,
  308.  * DevExpunge(lib) must remove the device itself as shown below.
  309.  */
  310.  
  311. long
  312. DevExpunge(D2, D3, dev)
  313. ulong        D2,
  314.         D3;
  315. DEV           *dev;
  316. {
  317.     long        Seglist;
  318.  
  319.     if (dev->dev_OpenCnt) {
  320.     dev->dev_Flags |= LIBF_DELEXP;
  321.     return (NULL);
  322.     }
  323.     Remove(dev);
  324.     DevCloseDown(dev);          /* Should be quick! */
  325. #ifdef DEBUG
  326.     dbuninit();
  327. #endif
  328.     Seglist = dev->md_Seglist;
  329.     FreeMem((char *) dev - dev->dev_NegSize,
  330.         (long) dev->dev_NegSize + dev->dev_PosSize);
  331.     return (Seglist);
  332. }
  333.  
  334. /*
  335.  * BeginIO entry point. We don't handle any QUICK requests, we just send
  336.  * the request to the proper unit to handle.
  337.  */
  338.  
  339. void
  340. DevBeginIO(D2, D3, ioreq, dev)
  341. ulong        D2,
  342.         D3;
  343. register struct IOStdReq *ioreq;
  344. DEV           *dev;
  345. {
  346.     UNIT       *unit;
  347.  
  348.     /*
  349.      * Bookkeeping.
  350.      */
  351.     unit = (UNIT *) ioreq->io_Unit;
  352.     debug(("BeginIO: io %08lx dev %08lx u %08lx\n", ioreq, dev, unit));
  353.  
  354.     /*
  355.      * See if the io command is within range.
  356.      */
  357.     if (STRIP(ioreq->io_Command) > TD_LASTCOMM)
  358.     goto NoCmd;
  359.  
  360. #ifdef HANDLE_IO_QUICK
  361.     Forbid();                   /* Disable(); is a bit too strong for us. */
  362. #endif
  363.  
  364.     /*
  365.      * Process all immediate commands no matter what. Don't even require
  366.      * an exclusive lock on the unit.
  367.      */
  368.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  369.     goto Immediate;
  370.  
  371.     /*
  372.      * We don't handle any QUICK I/O since that only gives trouble with
  373.      * message ports and so. Other devices normally would include the code
  374.      * below.
  375.      */
  376. #ifdef HANDLE_IO_QUICK
  377.     /*
  378.      * See if the user does not request QUICK IO. If not, it is likely to
  379.      * be async and therefore we don't do it sync.
  380.      */
  381.     if (!(ioreq->io_Flags & IOF_QUICK))
  382.     goto NoQuickRequested;
  383.  
  384.     /*
  385.      * See if the unit is STOPPED. If so, queue the msg.
  386.      */
  387.     if (unit->mu_Flags & UNITF_STOPPED)
  388.     goto QueueMsg;
  389.  
  390.     /*
  391.      * This is not an immediate command. See if the device is busy. If
  392.      * not, process the action in this (the caller's) context.
  393.      */
  394.     if (!BSET_ACTIVE(&unit->mu_Flags))
  395.     goto Immediate;
  396. #endif
  397.  
  398.     /*
  399.      * We need to queue the device. Clear the QUICK flag.
  400.      */
  401. QueueMsg:
  402.     ioreq->io_Flags &= ~IOF_QUICK;
  403. NoQuickRequested:
  404. #ifdef HANDLE_IO_QUICK
  405.     Permit();                   /* Enable(); is a bit too strong for us. */
  406. #endif
  407.     PutMsg(&unit->mu_Port, ioreq);
  408.  
  409.     return;
  410.  
  411. Immediate:
  412. #ifdef HANDLE_IO_QUICK
  413.     Permit();                   /* Enable(); is a bit too strong for us. */
  414. #endif
  415.     debug(("BeginIO: Immediate\n"));
  416.     ioreq->io_Error = TDERR_NoError;
  417.     PerformIO(ioreq, unit);
  418.     return;
  419.  
  420. NoCmd:
  421.     ioreq->io_Error = IOERR_NOCMD;
  422.     TermIO(ioreq);
  423.     return;
  424.  
  425. }
  426.  
  427. /*
  428.  * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  429.  * commands that don't call TermIO, or call it multiple times, may not be
  430.  * properly handled unless you are careful. TD_ADDCHANGEINT and
  431.  * TD_REMCHANGEINT are obvious examples.
  432.  */
  433.  
  434. void
  435. TermIO(ioreq)
  436. register struct IOStdReq *ioreq;
  437. {
  438.     register UNIT  *unit;
  439.  
  440.     unit = (UNIT *) ioreq->io_Unit;
  441.     debug(("TermIO: io %08lx u %08lx %ld %d\n", ioreq, unit,
  442.        ioreq->io_Actual, ioreq->io_Error));
  443.  
  444. #ifdef HANDLE_IO_QUICK
  445.     /*
  446.      * Since immediate commands don't even require an exclusive lock on
  447.      * the unit, don't unlock it.
  448.      */
  449.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  450.     goto Immediate;
  451.  
  452.     /*
  453.      * We may need to turn the active (lock) bit off, but not if we are
  454.      * within the task.
  455.      */
  456.     if (unit->mu_Flags & UNITF_INTASK)
  457.     goto Immediate;
  458.  
  459.     unit->mu_Flags &= ~UNITF_ACTIVE;
  460.  
  461.     /*
  462.      * The task may have work to do that came in while we were processing
  463.      * in the caller's context.
  464.      */
  465.     if (unit->mu_Flags & UNITF_WAKETASK) {
  466.     unit->mu_Flags &= ~UNITF_WAKETASK;
  467.     WakePort(&unit->mu_Port);
  468.     }
  469. #endif
  470.  
  471. Immediate:
  472.     /*
  473.      * If the quick bit is still set then wen don't need to reply the msg
  474.      * -- just return to the user.
  475.      */
  476.  
  477.     if (!(ioreq->io_Flags & IOF_QUICK))
  478.     ReplyMsg(&ioreq->io_Message);
  479.  
  480.     return;
  481. }
  482.  
  483. /*
  484.  * AbortIO entry point. We don't abort IO here.
  485.  */
  486.  
  487. long
  488. DevAbortIO(D2, D3, ioreq, dev)
  489. ulong        D2,
  490.         D3;
  491. DEV           *dev;
  492. struct IOStdReq *ioreq;
  493. {
  494.     return 1;
  495. }
  496.  
  497. void
  498. WakePort(port)
  499. register struct MsgPort *port;
  500. {
  501.     Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  502. }
  503.  
  504. /*
  505.  * This is the main loop of the Unit tasks. It must be very careful with
  506.  * global data.
  507.  */
  508.  
  509. void
  510. UnitTask()
  511. {
  512.     /* DEV *dev; */
  513.     UNIT       *unit;
  514.     long        waitmask;
  515.     struct IOExtTD *ioreq;
  516.  
  517.     {
  518.     struct Task    *task,
  519.                *FindTask();
  520.  
  521.     task = FindTask(NULL);
  522.     unit = (UNIT *) task->tc_UserData;
  523.     /* dev = unit->mu_Dev; */
  524.     task->tc_UserData = NULL;
  525.     }
  526.  
  527.     /*
  528.      * Now finish initializing the message ports and other signal things
  529.      */
  530.  
  531.     {
  532.     byte        sigbit;
  533.  
  534.     unit->mu_DiskReplyPort.mp_SigBit = AllocSignal(-1L);
  535.     unit->mu_DiskReplyPort.mp_Flags = PA_SIGNAL;
  536.  
  537.     sigbit = AllocSignal(-1L);
  538.     unit->mu_Port.mp_SigBit = sigbit;
  539.     unit->mu_Port.mp_Flags = PA_SIGNAL;
  540.     waitmask = 1L << sigbit;
  541.  
  542.     unit->mu_DmaSignal = AllocSignal(-1L);
  543.     }
  544.  
  545.     for (;;) {
  546.     debug(("Task: Waiting... "));
  547.     Wait(waitmask);
  548.  
  549.     /*
  550.      * See if we are stopped.
  551.      */
  552.     if (unit->mu_Flags & UNITF_STOPPED)
  553.         continue;
  554.  
  555. #ifdef HANDLE_IO_QUICK
  556.     /*
  557.      * Lock the device. If it fails, we have set a flag such that the
  558.      * TermIO wakes us again.
  559.      */
  560.     unit->mu_Flags |= UNITF_WAKETASK;
  561.     if (BSET_ACTIVE(&unit->mu_Flags))
  562.         continue;
  563.  
  564.     unit->mu_Flags |= UNITF_INTASK;
  565. #endif
  566.  
  567.     while (ioreq = (struct IOExtTD *) GetMsg(&unit->mu_Port)) {
  568.         debug(("Task: io %08lx %x\n", ioreq, ioreq->iotd_Req.io_Command));
  569.         ioreq->iotd_Req.io_Error = 0;
  570.         PerformIO((&ioreq->iotd_Req), unit);
  571.     }
  572.  
  573. #ifdef HANDLE_IO_QUICK
  574.     unit->mu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  575. #endif
  576.     }
  577. }
  578.  
  579. void
  580. CMD_Invalid(ioreq, unit)
  581. struct IOStdReq *ioreq;
  582. UNIT           *unit;
  583. {
  584.     ioreq->io_Error = IOERR_NOCMD;
  585.     TermIO(ioreq);
  586. }
  587.  
  588. void
  589. CMD_Stop(ioreq, unit)
  590. struct IOExtTD *ioreq;
  591. UNIT           *unit;
  592. {
  593.     unit->mu_Flags |= UNITF_STOPPED;
  594.     TermIO(ioreq);
  595. }
  596.  
  597. void
  598. CMD_Start(ioreq, unit)
  599. struct IOExtTD *ioreq;
  600. UNIT           *unit;
  601. {
  602.     unit->mu_Flags &= ~UNITF_STOPPED;
  603.     WakePort(&unit->mu_Port);
  604.     TermIO(ioreq);
  605. }
  606.  
  607. void
  608. CMD_Flush(ioreq, unit)
  609. struct IOExtTD *ioreq;
  610. UNIT           *unit;
  611. {
  612.     register struct IOStdReq *req;
  613.  
  614.     /* Flush our own command queue */
  615.     Forbid();
  616.     while (req = (struct IOStdReq *) GetMsg(unit->mu_Port)) {
  617.     req->io_Error = IOERR_ABORTED;
  618.     ReplyMsg(&req->io_Message);
  619.     }
  620.     Permit();
  621.  
  622.     WakePort(&unit->mu_Port);
  623.     TermIO(ioreq);
  624. }
  625.  
  626. void
  627. TrackdiskGateway(ioreq, unit)
  628. register struct IOExtTD *ioreq;
  629. UNIT           *unit;
  630. {
  631.     register struct IOExtTD *tdioreq;
  632.  
  633.     debug(("Trackdisk: %x ", ioreq->iotd_Req.io_Command));
  634.     tdioreq = unit->mu_DiskIOReq;
  635.  
  636.     /*
  637.      * Clone almost the entire io request to relay to the
  638.      * trackdisk.device.
  639.      */
  640.  
  641.     tdioreq->iotd_Req.io_Command = ioreq->iotd_Req.io_Command;
  642.     tdioreq->iotd_Req.io_Flags = ioreq->iotd_Req.io_Flags | IOF_QUICK;
  643.     tdioreq->iotd_Req.io_Length = ioreq->iotd_Req.io_Length;
  644.     tdioreq->iotd_Req.io_Data = ioreq->iotd_Req.io_Data;
  645.     tdioreq->iotd_Req.io_Offset = ioreq->iotd_Req.io_Offset;
  646.     if (ioreq->iotd_Req.io_Command & TDF_EXTCOM) {
  647.     tdioreq->iotd_Count = ioreq->iotd_Count;
  648.     tdioreq->iotd_SecLabel = ioreq->iotd_SecLabel;
  649.     }
  650.     BeginIO(tdioreq);
  651.     WaitIO(tdioreq);
  652.  
  653.     ioreq->iotd_Req.io_Error = tdioreq->iotd_Req.io_Error;
  654.     ioreq->iotd_Req.io_Actual = tdioreq->iotd_Req.io_Actual;
  655.  
  656.     TermIO(ioreq);
  657. }
  658.  
  659. #ifdef DEBUG
  660. /* DEBUGGING                */
  661. struct MsgPort *Dbport;     /* owned by the debug process        */
  662. struct MsgPort *Dback;        /* owned by the DOS device driver  */
  663. short        DBEnable;
  664. struct SignalSemaphore PortUse;
  665.  
  666. #define CTOB(x) (void *)(((long)(x))>>2)        /* BCPL conversion */
  667.  
  668. /*
  669.  * DEBUGGING CODE.    You cannot make DOS library calls that access
  670.  * other devices from within a device driver because the caller may not be
  671.  * a process.  If you need to make such calls you must create a port and
  672.  * construct the DOS messages yourself.  I do not do this.  To get
  673.  * debugging info out another PROCESS is created to which debugging
  674.  * messages can be sent. The replyport gets a new SigTask for every
  675.  * dbprintf call, therefore the semaphore.
  676.  */
  677.  
  678. extern void    debugproc();
  679. struct Library *DOSBase,
  680.            *OpenLibrary();
  681.  
  682. dbinit()
  683. {
  684.     struct Task    *task = FindTask(NULL);
  685.  
  686.     DOSBase = OpenLibrary("dos.library", 0L);
  687.     Dback = CreatePort("Dback", -1L);
  688.     FreeSignal((long) Dback->mp_SigBit);
  689.     Dback->mp_SigBit = 2;
  690.     InitSemaphore(&PortUse);
  691.     CreateProc("messydisk_DB", (long) TASKPRI + 1, CTOB(debugproc), 2000L);
  692.     WaitPort(Dback);            /* handshake startup    */
  693.     GetMsg(Dback);              /* remove dummy msg     */
  694.     DBEnable = 1;
  695.     dbprintf("Debugger running V1.11\n");
  696. }
  697.  
  698. dbuninit()
  699. {
  700.     struct Message  killmsg;
  701.  
  702.     if (Dbport) {
  703.     killmsg.mn_Length = 0;    /* 0 means die        */
  704.     ObtainSemaphore(&PortUse);
  705.     Dback->mp_SigTask = FindTask(NULL);
  706.     PutMsg(Dbport, &killmsg);
  707.     WaitPort(Dback);        /* He's dead jim!      */
  708.     GetMsg(Dback);
  709.     ReleaseSemaphore(&PortUse);
  710.     Dback->mp_SigBit = -1;
  711.     DeletePort(Dback);
  712.  
  713.     /*
  714.      * Since the debug process is running at a greater priority, I am
  715.      * pretty sure that it is guarenteed to be completely removed
  716.      * before this task gets control again.
  717.      */
  718.     }
  719.     CloseLibrary(DOSBase);
  720. }
  721.  
  722. dbprintf(a, b, c, d, e, f, g, h, i, j)
  723. long        a, b, c, d, e, f, g, h, i, j;
  724. {
  725.     struct {
  726.     struct Message    msg;
  727.     char        buf[256];
  728.     }            msgbuf;
  729.     register struct Message *msg = &msgbuf.msg;
  730.     register long   len;
  731.  
  732.     if (Dbport && DBEnable) {
  733.     ObtainSemaphore(&PortUse);      /* sprintf is not re-entrant */
  734.     sprintf(msgbuf.buf, a, b, c, d, e, f, g, h, i, j);
  735.     len = strlen(msgbuf.buf) + 1;
  736.     msg->mn_Length = len;    /* Length NEVER 0     */
  737.     Dback->mp_SigTask = FindTask(NULL);
  738.     PutMsg(Dbport, msg);
  739.     WaitPort(Dback);
  740.     GetMsg(Dback);
  741.     ReleaseSemaphore(&PortUse);
  742.     }
  743. }
  744.  
  745. /*
  746.  * BTW, the DOS library used by debugmain() was actually opened by the
  747.  * opener of the device driver.
  748.  */
  749.  
  750. debugmain()
  751. {
  752.     register struct Message *msg;
  753.     register long   len;
  754.     register void  *fh,
  755.            *Open();
  756.     void       *fh2;
  757.     struct Message  DummyMsg;
  758.  
  759.     Dbport = CreatePort("Dbport", -1L);
  760.     fh = Open("CON:0/20/640/101/Device debug", MODE_NEWFILE);
  761.     fh2 = Open("PAR:", MODE_OLDFILE);
  762.     PutMsg(Dback, &DummyMsg);
  763.     for (;;) {
  764.     WaitPort(Dbport);
  765.     msg = GetMsg(Dbport);
  766.     len = msg->mn_Length;
  767.     if (len == 0)
  768.         break;
  769.     --len;            /* Fix length up     */
  770.     if (DBEnable & 1)
  771.         Write(fh, msg + 1, len);
  772.     if (DBEnable & 2)
  773.         Write(fh2, msg + 1, len);
  774.     PutMsg(Dback, msg);
  775.     }
  776.     Close(fh);
  777.     Close(fh2);
  778.     DeletePort(Dbport);
  779.     PutMsg(Dback, msg);         /* Kill handshake  */
  780. }
  781.  
  782. /*
  783.  * The assembly tag for the DOS process:  CNOP causes alignment problems
  784.  * with the Aztec assembler for some reason.  I assume then, that the
  785.  * alignment is unknown.  Since the BCPL conversion basically zero's the
  786.  * lower two bits of the address the actual code may start anywhere within
  787.  * 8 bytes of address (remember the first longword is a segment pointer
  788.  * and skipped).  Sigh....  (see CreateProc() above).
  789.  */
  790. /* INDENT OFF */
  791. #asm
  792.     public    _debugproc
  793.     public    _debugmain
  794.  
  795.     cseg
  796. _debugproc:
  797.     nop
  798.     nop
  799.     nop
  800.     nop
  801.     nop
  802.     movem.l D2-D7/A2-A6,-(sp)
  803.     jsr    _debugmain
  804.     movem.l (sp)+,D2-D7/A2-A6
  805.     rts
  806. #endasm
  807.  
  808. #endif                /* DEBUG */
  809.